<!DOCTYPE html>
<html CN>







<head>
	
	
	<link rel="stylesheet" href="/css/allinone.min.css"> 

	
	<!-- Global Site Tag (gtag.js) - Google Analytics -->
	<script async src="https://www.googletagmanager.com/gtag/js?id=UA-42863699-1"></script>
	<script>
		window.dataLayer = window.dataLayer || [];
		function gtag(){dataLayer.push(arguments);}
		gtag('js', new Date());
		gtag('config', 'UA-42863699-1');
	</script>
	

	<meta charset="utf-8" />
	<meta http-equiv="X-UA-Compatible" content="IE=edge" />

	<title>kubelet 源码分析：Garbage Collect | Cizixs Write Here</title>

	<meta name="HandheldFriendly" content="True" />
	<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
	<meta name="generator" content="hexo">
	<meta name="author" content="Cizixs Wu">
	<meta name="description" content="">

	
	<meta name="keywords" content="">
	

	
	<link rel="shortcut icon" href="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg">
	

	
	<meta name="theme-color" content="#3c484e">
	<meta name="msapplication-TileColor" content="#3c484e">
	

	

	

	<meta property="og:site_name" content="Cizixs Write Here">
	<meta property="og:type" content="article">
	<meta property="og:title" content="kubelet 源码分析：Garbage Collect | Cizixs Write Here">
	<meta property="og:description" content="">
	<meta property="og:url" content="http://cizixs.com/2017/06/09/kubelet-source-code-analysis-part-3/">

	
	<meta property="article:published_time" content="2017-06-09T00:06:00+08:00"/> 
	<meta property="article:author" content="Cizixs Wu">
	<meta property="article:published_first" content="Cizixs Write Here, /2017/06/09/kubelet-source-code-analysis-part-3/" />
	

	
	
	<script src="https://cdn.staticfile.org/jquery/3.2.1/jquery.min.js"></script>
	

	
	<script src="https://cdn.staticfile.org/highlight.js/9.10.0/highlight.min.js"></script>
	

	
	
<link rel="stylesheet" href="/css/prism-base16-ateliersulphurpool.light.css" type="text/css"></head>
<body class="post-template">
    <div class="site-wrapper">
        




<header class="site-header outer" style="z-index: 999">
    <div class="inner">
        
<nav class="site-nav"> 
    <div class="site-nav-left">
        <ul class="nav">
            <li>
                
                <a href="/" title="Home">Home</a>
                
            </li>
            
            
            <li>
                <a href="/about" title="About">About</a>
            </li>
            
            <li>
                <a href="/archives" title="Archives">Archives</a>
            </li>
            
            
        </ul> 
    </div>
    <div class="site-nav-right">
        
<div class="social-links" >
    
    <a class="social-link" title="weibo" href="https://weibo.com/1921727853" target="_blank" rel="noopener">
        <svg viewBox="0 0 1141 1024" xmlns="http://www.w3.org/2000/svg"><path d="M916.48 518.144q27.648 21.504 38.912 51.712t9.216 62.976-14.336 65.536-31.744 59.392q-34.816 48.128-78.848 81.92t-91.136 56.32-94.72 35.328-89.6 18.944-75.264 7.68-51.712 1.536-49.152-2.56-68.096-10.24-78.336-21.504-79.872-36.352-74.24-55.296-59.904-78.848q-16.384-29.696-22.016-63.488t-5.632-86.016q0-22.528 7.68-51.2t27.136-63.488 53.248-75.776 86.016-90.112q51.2-48.128 105.984-85.504t117.248-57.856q28.672-10.24 63.488-11.264t57.344 11.264q10.24 11.264 19.456 23.04t12.288 29.184q3.072 14.336 0.512 27.648t-5.632 26.624-5.12 25.6 2.048 22.528q17.408 2.048 33.792-1.536t31.744-9.216 31.232-11.776 33.28-9.216q27.648-5.12 54.784-4.608t49.152 7.68 36.352 22.016 17.408 38.4q2.048 14.336-2.048 26.624t-8.704 23.04-7.168 22.016 1.536 23.552q3.072 7.168 14.848 13.312t27.136 12.288 32.256 13.312 29.184 16.384zM658.432 836.608q26.624-16.384 53.76-45.056t44.032-64 18.944-75.776-20.48-81.408q-19.456-33.792-47.616-57.344t-62.976-37.376-74.24-19.968-80.384-6.144q-78.848 0-139.776 16.384t-105.472 43.008-72.192 60.416-38.912 68.608q-11.264 33.792-6.656 67.072t20.992 62.976 42.496 53.248 57.856 37.888q58.368 25.6 119.296 32.256t116.224 0.512 100.864-21.504 74.24-33.792zM524.288 513.024q20.48 8.192 38.912 18.432t32.768 27.648q10.24 12.288 17.92 30.72t10.752 39.424 1.536 42.496-9.728 38.912q-8.192 18.432-19.968 37.376t-28.672 35.328-40.448 29.184-57.344 18.944q-61.44 11.264-117.76-11.264t-88.064-74.752q-12.288-39.936-13.312-70.656t16.384-66.56q13.312-27.648 40.448-51.712t62.464-38.912 75.264-17.408 78.848 12.8zM361.472 764.928q37.888 3.072 57.856-18.432t21.504-48.128-15.36-47.616-52.736-16.896q-27.648 3.072-43.008 23.552t-17.408 43.52 9.728 42.496 39.424 21.504zM780.288 6.144q74.752 0 139.776 19.968t113.664 57.856 76.288 92.16 27.648 122.88q0 33.792-16.384 50.688t-35.328 17.408-35.328-14.336-16.384-45.568q0-40.96-22.528-77.824t-59.392-64.512-84.48-43.52-96.768-15.872q-31.744 0-47.104-15.36t-14.336-34.304 18.944-34.304 51.712-15.36zM780.288 169.984q95.232 0 144.384 48.64t49.152 146.944q0 30.72-10.24 43.52t-22.528 11.264-22.528-14.848-10.24-35.84q0-60.416-34.816-96.256t-93.184-35.84q-19.456 0-28.672-10.752t-9.216-23.04 9.728-23.04 28.16-10.752z" /></svg>
    </a>
    

    
    <a class="social-link" title="github" href="https://github.com/cizixs" target="_blank" rel="noopener">
        <svg viewBox="0 0 1049 1024" xmlns="http://www.w3.org/2000/svg"><path d="M524.979332 0C234.676191 0 0 234.676191 0 524.979332c0 232.068678 150.366597 428.501342 358.967656 498.035028 26.075132 5.215026 35.636014-11.299224 35.636014-25.205961 0-12.168395-0.869171-53.888607-0.869171-97.347161-146.020741 31.290159-176.441729-62.580318-176.441729-62.580318-23.467619-60.841976-58.234462-76.487055-58.234463-76.487055-47.804409-32.15933 3.476684-32.15933 3.476685-32.15933 53.019436 3.476684 80.83291 53.888607 80.83291 53.888607 46.935238 79.963739 122.553122 57.365291 152.97411 43.458554 4.345855-33.897672 18.252593-57.365291 33.028501-70.402857-116.468925-12.168395-239.022047-57.365291-239.022047-259.012982 0-57.365291 20.860106-104.300529 53.888607-140.805715-5.215026-13.037566-23.467619-66.926173 5.215027-139.067372 0 0 44.327725-13.906737 144.282399 53.888607 41.720212-11.299224 86.917108-17.383422 131.244833-17.383422s89.524621 6.084198 131.244833 17.383422C756.178839 203.386032 800.506564 217.29277 800.506564 217.29277c28.682646 72.1412 10.430053 126.029806 5.215026 139.067372 33.897672 36.505185 53.888607 83.440424 53.888607 140.805715 0 201.64769-122.553122 245.975415-239.891218 259.012982 19.121764 16.514251 35.636014 47.804409 35.636015 97.347161 0 70.402857-0.869171 126.898978-0.869172 144.282399 0 13.906737 9.560882 30.420988 35.636015 25.205961 208.601059-69.533686 358.967656-265.96635 358.967655-498.035028C1049.958663 234.676191 814.413301 0 524.979332 0z" /></svg>
    </a>
    

    
    <a class="social-link" title="stackoverflow" href="https://stackoverflow.com/users/1925083/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M15 21h-10v-2h10v2zm6-11.665l-1.621-9.335-1.993.346 1.62 9.335 1.994-.346zm-5.964 6.937l-9.746-.975-.186 2.016 9.755.879.177-1.92zm.538-2.587l-9.276-2.608-.526 1.954 9.306 2.5.496-1.846zm1.204-2.413l-8.297-4.864-1.029 1.743 8.298 4.865 1.028-1.744zm1.866-1.467l-5.339-7.829-1.672 1.14 5.339 7.829 1.672-1.14zm-2.644 4.195v8h-12v-8h-2v10h16v-10h-2z"/></svg>
    </a>
    

    

    
    <a class="social-link" title="twitter" href="https://twitter.com/cizixs" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"/></svg>

    </a>
    

    
    <a class="social-link" title="instagram" href="https://www.instagram.com/cizixs/" target="_blank" rel="noopener">
        <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 0-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"/></svg>
    </a>
    
    
    
</div>
    </div>
</nav>
    </div>
</header>


<main id="site-main" class="site-main outer" role="main">
    <div class="inner">
        <header class="post-full-header">
            <section class="post-full-meta">
                <time  class="post-full-meta-date" datetime="2017-06-08T16:00:00.000Z" itemprop="datePublished">
                    2017-06-9
                </time>
                
                <span class="date-divider">/</span>
                
                <a href="/categories/blog/">blog</a>&nbsp;&nbsp;
                
                
            </section>
            <h1 class="post-full-title">kubelet 源码分析：Garbage Collect</h1>
        </header>
        <article class="post-full no-image">
            
            <section class="post-full-content">
                <div id="lightgallery" class="markdown-body">
                    <h2 id="kubernetes-GC-简介"><a href="#kubernetes-GC-简介" class="headerlink" title="kubernetes GC 简介"></a>kubernetes GC 简介</h2><p>作为 kubernetes 中重要的组件，kubelet 接管了节点上容器相关的所有工作。除了最核心的任务：根据 apiserver 分配的 pod 创建容器之外，它还有其他很多事情要做，其中之一就是 GC（Garbage Collect）。</p>
<p>在运行一段时候之后，节点上会下载很多镜像，也会有很多因为各种原因退出的容器。为了保证节点能够正常运行，kubelet 要防止镜像太多占满磁盘空间，也要防止退出的容器太多导致系统运行缓慢或者出现错误。</p>
<p>GC 的工作不需要手动干预，kubelet 会周期性去执行，不过在启动 kubelet 进程的时候可以通过参数控制 GC 的策略。这篇文章会介绍 GC 的功能，然后跟着代码看一下它的实现。</p>
<h3 id="容器-Garbage-Collect"><a href="#容器-Garbage-Collect" class="headerlink" title="容器 Garbage Collect"></a>容器 Garbage Collect</h3><p>退出的容器也会继续占用系统资源，比如还会在文件系统存储很多数据、docker 应用也要占用 CPU 和内存去维护这些容器。docker 本身并不会自动删除已经退出的容器，因此 kubelet 就负起了这个责任。kubelet 容器的回收是为了删除已经退出的容器以节省节点的空间，提升性能。</p>
<p>容器 GC 虽然有利于空间和性能，但是删除容器也会导致错误现场被清理，不利于 debug 和错误定位，因此不建议把所有退出的容器都删除。因此容器的清理需要一定的策略，主要是告诉 kubelet 你要保存多少已经退出的容器。和容器 GC 有关的可以配置的 kubelet 启动参数包括：</p>
<ul>
<li><code>minimum-container-ttl-duration</code>：container 结束多长时间之后才能够被回收，默认是一分钟</li>
<li><code>maximum-dead-containers-per-container</code>：每个 container 最终可以保存多少个已经结束的容器，默认是 1，设置为负数表示不做限制</li>
<li><code>maximum-dead-containers</code>：节点上最多能保留多少个结束的容器，默认是 -1，表示不做限制</li>
</ul>
<p>也就是说默认情况下，kubelet 会自动每分钟去做容器 GC，容器退出一分钟之后就可以被删除，而且每个容器做多只会保留一个已经退出的历史容器。</p>
<h3 id="镜像-Garbage-Collect"><a href="#镜像-Garbage-Collect" class="headerlink" title="镜像 Garbage Collect"></a>镜像 Garbage Collect</h3><p>镜像主要占用磁盘空间，虽然 docker 使用镜像分层可以让多个镜像共享存储，但是长时间运行的节点如果下载了很多镜像也会导致占用的存储空间过多。如果镜像导致磁盘被占满，会造成应用无法正常工作。docker 默认也不会做镜像清理，镜像一旦下载就会永远留在本地，除非被手动删除。</p>
<p>其实很多镜像并没有被实际使用，这些不用的镜像继续占用空间是非常大的浪费，也是巨大的隐患，因此 kubelet 也会周期性地去清理镜像。</p>
<p>镜像的清理和容器不同，是以占用的空间作为标准的，用户可以配置当镜像占据多大比例的存储空间时才进行清理。清理的时候会优先清理最久没有被使用的镜像，镜像被 pull 下来或者被容器使用都会更新它的最近使用时间。</p>
<p>启动 kubelet 的时候，可以配置这些参数控制镜像清理的策略：</p>
<ul>
<li><code>image-gc-high-threshold</code>：磁盘使用率的上限，当达到这一使用率的时候会触发镜像清理。默认值为 90%</li>
<li><code>image-gc-low-threshold</code>：磁盘使用率的下限，每次清理直到使用率低于这个值或者没有可以清理的镜像了才会停止.默认值为 80%</li>
<li><code>minimum-image-ttl-duration</code>：镜像最少这么久没有被使用才会被清理，可以使用 <code>h</code>（小时）、<code>m</code>（分钟）、<code>s</code>（秒）和 <code>ms</code>（毫秒）时间单位进行配置，默认是 <code>2m</code>(两分钟)</li>
</ul>
<p>也就是说，默认情况下，当镜像占满所在盘 90% 容量的时候，kubelet 就会进行清理，一直到镜像占用率低于 80% 为止。</p>
<h2 id="容器-GC-的代码分析"><a href="#容器-GC-的代码分析" class="headerlink" title="容器 GC 的代码分析"></a>容器 GC 的代码分析</h2><p>我们在之前<a href="http://cizixs.com/2017/06/06/kubelet-source-code-analysis-part-1">分析 kubelet 启动</a>的时候讲过，kubelet 会调用 <code>StartGarbageCollection</code> 启动 GC：</p>
<pre class=" language-go"><code class="language-go"><span class="token keyword">func</span> <span class="token punctuation">(</span>kl <span class="token operator">*</span>Kubelet<span class="token punctuation">)</span> <span class="token function">StartGarbageCollection</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    loggedContainerGCFailure <span class="token operator">:=</span> <span class="token boolean">false</span>
    <span class="token keyword">go</span> wait<span class="token punctuation">.</span><span class="token function">Until</span><span class="token punctuation">(</span><span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> err <span class="token operator">:=</span> kl<span class="token punctuation">.</span>containerGC<span class="token punctuation">.</span><span class="token function">GarbageCollect</span><span class="token punctuation">(</span>kl<span class="token punctuation">.</span>sourcesReady<span class="token punctuation">.</span><span class="token function">AllReady</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            kl<span class="token punctuation">.</span>recorder<span class="token punctuation">.</span><span class="token function">Eventf</span><span class="token punctuation">(</span>kl<span class="token punctuation">.</span>nodeRef<span class="token punctuation">,</span> api<span class="token punctuation">.</span>EventTypeWarning<span class="token punctuation">,</span> events<span class="token punctuation">.</span>ContainerGCFailed<span class="token punctuation">,</span> err<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            loggedContainerGCFailure <span class="token operator">=</span> <span class="token boolean">true</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">var</span> vLevel glog<span class="token punctuation">.</span>Level <span class="token operator">=</span> <span class="token number">4</span>
            <span class="token keyword">if</span> loggedContainerGCFailure <span class="token punctuation">{</span>
                vLevel <span class="token operator">=</span> <span class="token number">1</span>
                loggedContainerGCFailure <span class="token operator">=</span> <span class="token boolean">false</span>
            <span class="token punctuation">}</span>

            glog<span class="token punctuation">.</span><span class="token function">V</span><span class="token punctuation">(</span>vLevel<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Infof</span><span class="token punctuation">(</span><span class="token string">"Container garbage collection succeeded"</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> ContainerGCPeriod<span class="token punctuation">,</span> wait<span class="token punctuation">.</span>NeverStop<span class="token punctuation">)</span>

    loggedImageGCFailure <span class="token operator">:=</span> <span class="token boolean">false</span>
    <span class="token keyword">go</span> wait<span class="token punctuation">.</span><span class="token function">Until</span><span class="token punctuation">(</span><span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">if</span> err <span class="token operator">:=</span> kl<span class="token punctuation">.</span>imageManager<span class="token punctuation">.</span><span class="token function">GarbageCollect</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            kl<span class="token punctuation">.</span>recorder<span class="token punctuation">.</span><span class="token function">Eventf</span><span class="token punctuation">(</span>kl<span class="token punctuation">.</span>nodeRef<span class="token punctuation">,</span> api<span class="token punctuation">.</span>EventTypeWarning<span class="token punctuation">,</span> events<span class="token punctuation">.</span>ImageGCFailed<span class="token punctuation">,</span> err<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            loggedImageGCFailure <span class="token operator">=</span> <span class="token boolean">true</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            <span class="token keyword">var</span> vLevel glog<span class="token punctuation">.</span>Level <span class="token operator">=</span> <span class="token number">4</span>
            <span class="token keyword">if</span> loggedImageGCFailure <span class="token punctuation">{</span>
                vLevel <span class="token operator">=</span> <span class="token number">1</span>
                loggedImageGCFailure <span class="token operator">=</span> <span class="token boolean">false</span>
            <span class="token punctuation">}</span>

            glog<span class="token punctuation">.</span><span class="token function">V</span><span class="token punctuation">(</span>vLevel<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Infof</span><span class="token punctuation">(</span><span class="token string">"Image garbage collection succeeded"</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> ImageGCPeriod<span class="token punctuation">,</span> wait<span class="token punctuation">.</span>NeverStop<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>容器 GC 和镜像 GC 分别是在独立的 goroutine 中执行的，我们先来分析容器 GC 的过程。containerGC 的创建是在 <code>pkg/kubelet/kubelet.go#NewMainKublet</code> 中完成的，对应的代码有：</p>
<pre class=" language-go"><code class="language-go">containerGCPolicy <span class="token operator">:=</span> kubecontainer<span class="token punctuation">.</span>ContainerGCPolicy<span class="token punctuation">{</span>
    MinAge<span class="token punctuation">:</span>             kubeCfg<span class="token punctuation">.</span>MinimumGCAge<span class="token punctuation">.</span>Duration<span class="token punctuation">,</span>
    MaxPerPodContainer<span class="token punctuation">:</span> <span class="token function">int</span><span class="token punctuation">(</span>kubeCfg<span class="token punctuation">.</span>MaxPerPodContainerCount<span class="token punctuation">)</span><span class="token punctuation">,</span>
    MaxContainers<span class="token punctuation">:</span>      <span class="token function">int</span><span class="token punctuation">(</span>kubeCfg<span class="token punctuation">.</span>MaxContainerCount<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span>

containerGC<span class="token punctuation">,</span> err <span class="token operator">:=</span> kubecontainer<span class="token punctuation">.</span><span class="token function">NewContainerGC</span><span class="token punctuation">(</span>klet<span class="token punctuation">.</span>containerRuntime<span class="token punctuation">,</span> containerGCPolicy<span class="token punctuation">)</span>
<span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> err
<span class="token punctuation">}</span>
klet<span class="token punctuation">.</span>containerGC <span class="token operator">=</span> containerGC
klet<span class="token punctuation">.</span>containerDeletor <span class="token operator">=</span> <span class="token function">newPodContainerDeletor</span><span class="token punctuation">(</span>klet<span class="token punctuation">.</span>containerRuntime<span class="token punctuation">,</span> integer<span class="token punctuation">.</span><span class="token function">IntMax</span><span class="token punctuation">(</span>containerGCPolicy<span class="token punctuation">.</span>MaxPerPodContainer<span class="token punctuation">,</span> minDeadContainerInPod<span class="token punctuation">)</span><span class="token punctuation">)</span>
</code></pre>
<p><code>containerGCPolicy</code> 对应了我们上面提到的容器 GC 的策略，具体的初始化和实现的代码在 <code>pkg/kubelet/container/container_gc.go</code> 文件中：</p>
<pre class=" language-go"><code class="language-go"><span class="token keyword">type</span> ContainerGCPolicy <span class="token keyword">struct</span> <span class="token punctuation">{</span>
    MinAge time<span class="token punctuation">.</span>Duration
    MaxPerPodContainer <span class="token builtin">int</span>
    MaxContainers <span class="token builtin">int</span>
<span class="token punctuation">}</span>

<span class="token keyword">type</span> ContainerGC <span class="token keyword">interface</span> <span class="token punctuation">{</span>
    <span class="token function">GarbageCollect</span><span class="token punctuation">(</span>allSourcesReady <span class="token builtin">bool</span><span class="token punctuation">)</span> <span class="token builtin">error</span>
<span class="token punctuation">}</span>

<span class="token keyword">type</span> realContainerGC <span class="token keyword">struct</span> <span class="token punctuation">{</span>
    runtime Runtime
    policy ContainerGCPolicy
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">NewContainerGC</span><span class="token punctuation">(</span>runtime Runtime<span class="token punctuation">,</span> policy ContainerGCPolicy<span class="token punctuation">)</span> <span class="token punctuation">(</span>ContainerGC<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span> policy<span class="token punctuation">.</span>MinAge <span class="token operator">&lt;</span> <span class="token number">0</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token boolean">nil</span><span class="token punctuation">,</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">"invalid minimum garbage collection age: %v"</span><span class="token punctuation">,</span> policy<span class="token punctuation">.</span>MinAge<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> <span class="token operator">&amp;</span>realContainerGC<span class="token punctuation">{</span>
        runtime<span class="token punctuation">:</span> runtime<span class="token punctuation">,</span>
        policy<span class="token punctuation">:</span>  policy<span class="token punctuation">,</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>cgc <span class="token operator">*</span>realContainerGC<span class="token punctuation">)</span> <span class="token function">GarbageCollect</span><span class="token punctuation">(</span>allSourcesReady <span class="token builtin">bool</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> cgc<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span><span class="token function">GarbageCollect</span><span class="token punctuation">(</span>cgc<span class="token punctuation">.</span>policy<span class="token punctuation">,</span> allSourcesReady<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>这里的代码只是一层封装，最终会调用 <code>runtime.GarbageCollect</code>，对于 docker 来说，对应的代码是 <code>pkg/kubelet/dockertools/docker_manager.go</code>：</p>
<pre class=" language-go"><code class="language-go"><span class="token keyword">func</span> <span class="token punctuation">(</span>dm <span class="token operator">*</span>DockerManager<span class="token punctuation">)</span> <span class="token function">GarbageCollect</span><span class="token punctuation">(</span>gcPolicy kubecontainer<span class="token punctuation">.</span>ContainerGCPolicy<span class="token punctuation">,</span> allSourcesReady <span class="token builtin">bool</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> dm<span class="token punctuation">.</span>containerGC<span class="token punctuation">.</span><span class="token function">GarbageCollect</span><span class="token punctuation">(</span>gcPolicy<span class="token punctuation">,</span> allSourcesReady<span class="token punctuation">)</span>
<span class="token punctuation">}</span>
</code></pre>
<p>内容又被包装到 <code>dm.containerGC</code>，我们找到创建 dockerManager 的代码，看一下 <code>containerGC</code> 初始化部分：</p>
<pre class=" language-go"><code class="language-go"><span class="token keyword">func</span> <span class="token function">NewDockerManager</span><span class="token punctuation">(</span><span class="token operator">...</span><span class="token punctuation">)</span><span class="token punctuation">{</span>
    <span class="token operator">...</span>
    dm<span class="token punctuation">.</span>containerGC <span class="token operator">=</span> <span class="token function">NewContainerGC</span><span class="token punctuation">(</span>client<span class="token punctuation">,</span> podGetter<span class="token punctuation">,</span> containerLogsDir<span class="token punctuation">)</span>
    <span class="token operator">...</span>
<span class="token punctuation">}</span>
</code></pre>
<p>这才是具体的 docker container GC 的实现， 对应的代码在 <code>pkg/kubelet/dockertools/container_gc.go#NewContainerGC</code>：</p>
<pre class=" language-go"><code class="language-go"><span class="token keyword">type</span> containerGC <span class="token keyword">struct</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// client 用来和 docker API 交互，比如获取容器列表、查看某个容器的详细信息等</span>
    client           DockerInterface
    podGetter        podGetter
    containerLogsDir <span class="token builtin">string</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token function">NewContainerGC</span><span class="token punctuation">(</span>client DockerInterface<span class="token punctuation">,</span> podGetter podGetter<span class="token punctuation">,</span> containerLogsDir <span class="token builtin">string</span><span class="token punctuation">)</span> <span class="token operator">*</span>containerGC <span class="token punctuation">{</span>
    <span class="token keyword">return</span> <span class="token operator">&amp;</span>containerGC<span class="token punctuation">{</span>
        client<span class="token punctuation">:</span>           client<span class="token punctuation">,</span>
        podGetter<span class="token punctuation">:</span>        podGetter<span class="token punctuation">,</span>
        containerLogsDir<span class="token punctuation">:</span> containerLogsDir<span class="token punctuation">,</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>cgc <span class="token operator">*</span>containerGC<span class="token punctuation">)</span> <span class="token function">GarbageCollect</span><span class="token punctuation">(</span>gcPolicy kubecontainer<span class="token punctuation">.</span>ContainerGCPolicy<span class="token punctuation">,</span> allSourcesReady <span class="token builtin">bool</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// 找到可以清理的容器列表，条件是不在运行并且创建时间超过 MinAge。</span>
    <span class="token comment" spellcheck="true">// 这个步骤会过滤掉不是 kubelet 管理的容器，并且把容器按照创建时间进行排序（也就是说最早创建的容器会先被删除）</span>
    <span class="token comment" spellcheck="true">// evictUnits 返回的是需要被正确回收的，第二个参数是 kubelet 无法识别的容器</span>
    evictUnits<span class="token punctuation">,</span> unidentifiedContainers<span class="token punctuation">,</span> err <span class="token operator">:=</span> cgc<span class="token punctuation">.</span><span class="token function">evictableContainers</span><span class="token punctuation">(</span>gcPolicy<span class="token punctuation">.</span>MinAge<span class="token punctuation">)</span>
    <span class="token operator">...</span><span class="token operator">...</span>

    <span class="token comment" spellcheck="true">// 删除无法识别的容器</span>
    <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> container <span class="token operator">:=</span> <span class="token keyword">range</span> unidentifiedContainers <span class="token punctuation">{</span>
        glog<span class="token punctuation">.</span><span class="token function">Infof</span><span class="token punctuation">(</span><span class="token string">"Removing unidentified dead container %q with ID %q"</span><span class="token punctuation">,</span> container<span class="token punctuation">.</span>name<span class="token punctuation">,</span> container<span class="token punctuation">.</span>id<span class="token punctuation">)</span>
        err <span class="token operator">=</span> cgc<span class="token punctuation">.</span>client<span class="token punctuation">.</span><span class="token function">RemoveContainer</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>id<span class="token punctuation">,</span> dockertypes<span class="token punctuation">.</span>ContainerRemoveOptions<span class="token punctuation">{</span>RemoveVolumes<span class="token punctuation">:</span> <span class="token boolean">true</span><span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            glog<span class="token punctuation">.</span><span class="token function">Warningf</span><span class="token punctuation">(</span><span class="token string">"Failed to remove unidentified dead container %q: %v"</span><span class="token punctuation">,</span> container<span class="token punctuation">.</span>name<span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">// 如果 pod 已经不存在了，就删除其中所有的容器</span>
    <span class="token keyword">if</span> allSourcesReady <span class="token punctuation">{</span>
        <span class="token keyword">for</span> key<span class="token punctuation">,</span> unit <span class="token operator">:=</span> <span class="token keyword">range</span> evictUnits <span class="token punctuation">{</span>
            <span class="token keyword">if</span> cgc<span class="token punctuation">.</span><span class="token function">isPodDeleted</span><span class="token punctuation">(</span>key<span class="token punctuation">.</span>uid<span class="token punctuation">)</span> <span class="token punctuation">{</span>
                cgc<span class="token punctuation">.</span><span class="token function">removeOldestN</span><span class="token punctuation">(</span>unit<span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>unit<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token comment" spellcheck="true">// Remove all.</span>
                <span class="token function">delete</span><span class="token punctuation">(</span>evictUnits<span class="token punctuation">,</span> key<span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">// 执行 GC 策略，保证每个 POD 最多只能保存 MaxPerPodContainer 个已经退出的容器</span>
    <span class="token keyword">if</span> gcPolicy<span class="token punctuation">.</span>MaxPerPodContainer <span class="token operator">>=</span> <span class="token number">0</span> <span class="token punctuation">{</span>
        cgc<span class="token punctuation">.</span><span class="token function">enforceMaxContainersPerEvictUnit</span><span class="token punctuation">(</span>evictUnits<span class="token punctuation">,</span> gcPolicy<span class="token punctuation">.</span>MaxPerPodContainer<span class="token punctuation">)</span>
    <span class="token punctuation">}</span>

    <span class="token comment" spellcheck="true">// 执行 GC 策略，保证节点上最多有 MaxContainers 个已经退出的容器</span>
    <span class="token comment" spellcheck="true">// 先把最大容器数量平分到 pod，保证每个 pod 在平均数量以下；如果还不满足要求的数量，就按照时间顺序先删除最旧的容器</span>
    <span class="token keyword">if</span> gcPolicy<span class="token punctuation">.</span>MaxContainers <span class="token operator">>=</span> <span class="token number">0</span> <span class="token operator">&amp;&amp;</span> evictUnits<span class="token punctuation">.</span><span class="token function">NumContainers</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> gcPolicy<span class="token punctuation">.</span>MaxContainers <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// 先按照 pod 进行删除，每个 pod 能保留的容器数是总数的平均值</span>
        numContainersPerEvictUnit <span class="token operator">:=</span> gcPolicy<span class="token punctuation">.</span>MaxContainers <span class="token operator">/</span> evictUnits<span class="token punctuation">.</span><span class="token function">NumEvictUnits</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> numContainersPerEvictUnit <span class="token operator">&lt;</span> <span class="token number">1</span> <span class="token punctuation">{</span>
            numContainersPerEvictUnit <span class="token operator">=</span> <span class="token number">1</span>
        <span class="token punctuation">}</span>
        cgc<span class="token punctuation">.</span><span class="token function">enforceMaxContainersPerEvictUnit</span><span class="token punctuation">(</span>evictUnits<span class="token punctuation">,</span> numContainersPerEvictUnit<span class="token punctuation">)</span>

        <span class="token comment" spellcheck="true">// 如果还不满足数量要求，按照容器进行删除，先删除最老的</span>
        numContainers <span class="token operator">:=</span> evictUnits<span class="token punctuation">.</span><span class="token function">NumContainers</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> numContainers <span class="token operator">></span> gcPolicy<span class="token punctuation">.</span>MaxContainers <span class="token punctuation">{</span>
            flattened <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span>containerGCInfo<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> numContainers<span class="token punctuation">)</span>
            <span class="token keyword">for</span> uid <span class="token operator">:=</span> <span class="token keyword">range</span> evictUnits <span class="token punctuation">{</span>
                flattened <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>flattened<span class="token punctuation">,</span> evictUnits<span class="token punctuation">[</span>uid<span class="token punctuation">]</span><span class="token operator">...</span><span class="token punctuation">)</span>
            <span class="token punctuation">}</span>
            sort<span class="token punctuation">.</span><span class="token function">Sort</span><span class="token punctuation">(</span><span class="token function">byCreated</span><span class="token punctuation">(</span>flattened<span class="token punctuation">)</span><span class="token punctuation">)</span>

            cgc<span class="token punctuation">.</span><span class="token function">removeOldestN</span><span class="token punctuation">(</span>flattened<span class="token punctuation">,</span> numContainers<span class="token operator">-</span>gcPolicy<span class="token punctuation">.</span>MaxContainers<span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token operator">...</span><span class="token operator">...</span>
    <span class="token keyword">return</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>
</code></pre>
<p>这段代码才是容器 GC 的核心逻辑，它做的事情是这样的：</p>
<ul>
<li>先从正在运行的容器中找到可以被清理的，包括符合清理条件或者不被 kubelet 识别的容器</li>
<li>直接删除不能识别的容器，以及 pod 信息已经不存在的容器</li>
<li>根据配置的容器删除策略，对剩下的容器进行删除</li>
</ul>
<h2 id="镜像-GC-的代码"><a href="#镜像-GC-的代码" class="headerlink" title="镜像 GC 的代码"></a>镜像 GC 的代码</h2><p>看过了容器 GC 的代码逻辑，我们再来看看镜像 GC 的逻辑。因为两者非常类似，这里略过参数的引用、对象的初始化和调用链分析，直接分析最核心的逻辑代码，这部分内容在 <code>pkg/kubelet/images/image_gc_manager.go</code> 文件中：</p>
<pre class=" language-go"><code class="language-go"><span class="token keyword">type</span> ImageGCManager <span class="token keyword">interface</span> <span class="token punctuation">{</span>
    <span class="token function">GarbageCollect</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span>

    <span class="token comment" spellcheck="true">// Start async garbage collection of images.</span>
    <span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span>

    <span class="token function">GetImageList</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span>kubecontainer<span class="token punctuation">.</span>Image<span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span>

    <span class="token comment" spellcheck="true">// Delete all unused images and returns the number of bytes freed. The number of bytes freed is always returned.</span>
    <span class="token function">DeleteUnusedImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">int64</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token comment" spellcheck="true">// 镜像 GC 策略</span>
<span class="token keyword">type</span> ImageGCPolicy <span class="token keyword">struct</span> <span class="token punctuation">{</span>
    HighThresholdPercent <span class="token builtin">int</span>
    LowThresholdPercent <span class="token builtin">int</span>
    MinAge time<span class="token punctuation">.</span>Duration
<span class="token punctuation">}</span>

<span class="token keyword">type</span> realImageGCManager <span class="token keyword">struct</span> <span class="token punctuation">{</span>
    runtime container<span class="token punctuation">.</span>Runtime

    <span class="token comment" spellcheck="true">// 记录了当前使用的镜像</span>
    imageRecords     <span class="token keyword">map</span><span class="token punctuation">[</span><span class="token builtin">string</span><span class="token punctuation">]</span><span class="token operator">*</span>imageRecord
    imageRecordsLock sync<span class="token punctuation">.</span>Mutex

    policy ImageGCPolicy

    cadvisor cadvisor<span class="token punctuation">.</span>Interface
    recorder record<span class="token punctuation">.</span>EventRecorder
    nodeRef <span class="token operator">*</span>api<span class="token punctuation">.</span>ObjectReference
    initialized <span class="token builtin">bool</span>

    <span class="token comment" spellcheck="true">// imageCache is the cache of latest image list.</span>
    imageCache imageCache
<span class="token punctuation">}</span>

<span class="token keyword">type</span> imageRecord <span class="token keyword">struct</span> <span class="token punctuation">{</span>
    firstDetected time<span class="token punctuation">.</span>Time
    lastUsed time<span class="token punctuation">.</span>Time
    <span class="token comment" spellcheck="true">// Size of the image in bytes.</span>
    size <span class="token builtin">int64</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>im <span class="token operator">*</span>realImageGCManager<span class="token punctuation">)</span> <span class="token function">Start</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
    <span class="token keyword">go</span> wait<span class="token punctuation">.</span><span class="token function">Until</span><span class="token punctuation">(</span><span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token comment" spellcheck="true">// Initial detection make detected time "unknown" in the past.</span>
        <span class="token keyword">var</span> ts time<span class="token punctuation">.</span>Time
        <span class="token keyword">if</span> im<span class="token punctuation">.</span>initialized <span class="token punctuation">{</span>
            ts <span class="token operator">=</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
        err <span class="token operator">:=</span> im<span class="token punctuation">.</span><span class="token function">detectImages</span><span class="token punctuation">(</span>ts<span class="token punctuation">)</span>
        <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            glog<span class="token punctuation">.</span><span class="token function">Warningf</span><span class="token punctuation">(</span><span class="token string">"[imageGCManager] Failed to monitor images: %v"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            im<span class="token punctuation">.</span>initialized <span class="token operator">=</span> <span class="token boolean">true</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token operator">*</span>time<span class="token punctuation">.</span>Minute<span class="token punctuation">,</span> wait<span class="token punctuation">.</span>NeverStop<span class="token punctuation">)</span>

    <span class="token comment" spellcheck="true">// Start a goroutine periodically updates image cache.</span>
    <span class="token keyword">go</span> wait<span class="token punctuation">.</span><span class="token function">Until</span><span class="token punctuation">(</span><span class="token keyword">func</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        images<span class="token punctuation">,</span> err <span class="token operator">:=</span> im<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span><span class="token function">ListImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            glog<span class="token punctuation">.</span><span class="token function">Warningf</span><span class="token punctuation">(</span><span class="token string">"[imageGCManager] Failed to update image list: %v"</span><span class="token punctuation">,</span> err<span class="token punctuation">)</span>
        <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
            im<span class="token punctuation">.</span>imageCache<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span>images<span class="token punctuation">)</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token operator">*</span>time<span class="token punctuation">.</span>Second<span class="token punctuation">,</span> wait<span class="token punctuation">.</span>NeverStop<span class="token punctuation">)</span>

    <span class="token keyword">return</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>im <span class="token operator">*</span>realImageGCManager<span class="token punctuation">)</span> <span class="token function">GarbageCollect</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token builtin">error</span> <span class="token punctuation">{</span>
    <span class="token comment" spellcheck="true">// 从 cadvisor 中获取镜像所在文件系统的信息，包括磁盘的容量和当前的使用量</span>
    fsInfo<span class="token punctuation">,</span> err <span class="token operator">:=</span> im<span class="token punctuation">.</span>cadvisor<span class="token punctuation">.</span><span class="token function">ImagesFsInfo</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> err
    <span class="token punctuation">}</span>
    capacity <span class="token operator">:=</span> <span class="token function">int64</span><span class="token punctuation">(</span>fsInfo<span class="token punctuation">.</span>Capacity<span class="token punctuation">)</span>
    available <span class="token operator">:=</span> <span class="token function">int64</span><span class="token punctuation">(</span>fsInfo<span class="token punctuation">.</span>Available<span class="token punctuation">)</span>
    <span class="token operator">...</span><span class="token operator">...</span>

    <span class="token comment" spellcheck="true">// 如果镜像的磁盘使用率达到了设定的最高阈值，就进行清理工作，直到使用率</span>
    usagePercent <span class="token operator">:=</span> <span class="token number">100</span> <span class="token operator">-</span> <span class="token function">int</span><span class="token punctuation">(</span>available<span class="token operator">*</span><span class="token number">100</span><span class="token operator">/</span>capacity<span class="token punctuation">)</span>
    <span class="token keyword">if</span> usagePercent <span class="token operator">>=</span> im<span class="token punctuation">.</span>policy<span class="token punctuation">.</span>HighThresholdPercent <span class="token punctuation">{</span>
        amountToFree <span class="token operator">:=</span> capacity<span class="token operator">*</span><span class="token function">int64</span><span class="token punctuation">(</span><span class="token number">100</span><span class="token operator">-</span>im<span class="token punctuation">.</span>policy<span class="token punctuation">.</span>LowThresholdPercent<span class="token punctuation">)</span><span class="token operator">/</span><span class="token number">100</span> <span class="token operator">-</span> available
        glog<span class="token punctuation">.</span><span class="token function">Infof</span><span class="token punctuation">(</span><span class="token string">"[imageGCManager]: Disk usage on %q (%s) is at %d%% which is over the high threshold (%d%%). Trying to free %d bytes"</span><span class="token punctuation">,</span> fsInfo<span class="token punctuation">.</span>Device<span class="token punctuation">,</span> fsInfo<span class="token punctuation">.</span>Mountpoint<span class="token punctuation">,</span> usagePercent<span class="token punctuation">,</span> im<span class="token punctuation">.</span>policy<span class="token punctuation">.</span>HighThresholdPercent<span class="token punctuation">,</span> amountToFree<span class="token punctuation">)</span>
        freed<span class="token punctuation">,</span> err <span class="token operator">:=</span> im<span class="token punctuation">.</span><span class="token function">freeSpace</span><span class="token punctuation">(</span>amountToFree<span class="token punctuation">,</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            <span class="token keyword">return</span> err
        <span class="token punctuation">}</span>

        <span class="token keyword">if</span> freed <span class="token operator">&lt;</span> amountToFree <span class="token punctuation">{</span>
            err <span class="token operator">:=</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">"failed to garbage collect required amount of images. Wanted to free %d, but freed %d"</span><span class="token punctuation">,</span> amountToFree<span class="token punctuation">,</span> freed<span class="token punctuation">)</span>
            im<span class="token punctuation">.</span>recorder<span class="token punctuation">.</span><span class="token function">Eventf</span><span class="token punctuation">(</span>im<span class="token punctuation">.</span>nodeRef<span class="token punctuation">,</span> api<span class="token punctuation">.</span>EventTypeWarning<span class="token punctuation">,</span> events<span class="token punctuation">.</span>FreeDiskSpaceFailed<span class="token punctuation">,</span> err<span class="token punctuation">.</span><span class="token function">Error</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
            <span class="token keyword">return</span> err
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">return</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>im <span class="token operator">*</span>realImageGCManager<span class="token punctuation">)</span> <span class="token function">DeleteUnusedImages</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">int64</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">return</span> im<span class="token punctuation">.</span><span class="token function">freeSpace</span><span class="token punctuation">(</span>math<span class="token punctuation">.</span>MaxInt64<span class="token punctuation">,</span> time<span class="token punctuation">.</span><span class="token function">Now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span>

<span class="token keyword">func</span> <span class="token punctuation">(</span>im <span class="token operator">*</span>realImageGCManager<span class="token punctuation">)</span> <span class="token function">freeSpace</span><span class="token punctuation">(</span>bytesToFree <span class="token builtin">int64</span><span class="token punctuation">,</span> freeTime time<span class="token punctuation">.</span>Time<span class="token punctuation">)</span> <span class="token punctuation">(</span><span class="token builtin">int64</span><span class="token punctuation">,</span> <span class="token builtin">error</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>

    <span class="token comment" spellcheck="true">// 更新镜像记录列表中的数据，添加刚发现的镜像，移除已经不存在的镜像</span>
    err <span class="token operator">:=</span> im<span class="token punctuation">.</span><span class="token function">detectImages</span><span class="token punctuation">(</span>freeTime<span class="token punctuation">)</span>
    <span class="token operator">...</span><span class="token operator">...</span>

    im<span class="token punctuation">.</span>imageRecordsLock<span class="token punctuation">.</span><span class="token function">Lock</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token keyword">defer</span> im<span class="token punctuation">.</span>imageRecordsLock<span class="token punctuation">.</span><span class="token function">Unlock</span><span class="token punctuation">(</span><span class="token punctuation">)</span>

    <span class="token comment" spellcheck="true">// 根据镜像的最近使用时间和最近发现时间进行排序</span>
    images <span class="token operator">:=</span> <span class="token function">make</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token punctuation">]</span>evictionInfo<span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">,</span> <span class="token function">len</span><span class="token punctuation">(</span>im<span class="token punctuation">.</span>imageRecords<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token keyword">for</span> image<span class="token punctuation">,</span> record <span class="token operator">:=</span> <span class="token keyword">range</span> im<span class="token punctuation">.</span>imageRecords <span class="token punctuation">{</span>
        images <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>images<span class="token punctuation">,</span> evictionInfo<span class="token punctuation">{</span>
            id<span class="token punctuation">:</span>          image<span class="token punctuation">,</span>
            imageRecord<span class="token punctuation">:</span> <span class="token operator">*</span>record<span class="token punctuation">,</span>
        <span class="token punctuation">}</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    sort<span class="token punctuation">.</span><span class="token function">Sort</span><span class="token punctuation">(</span><span class="token function">byLastUsedAndDetected</span><span class="token punctuation">(</span>images<span class="token punctuation">)</span><span class="token punctuation">)</span>

    <span class="token comment" spellcheck="true">// Delete unused images until we've freed up enough space.</span>
    <span class="token keyword">var</span> deletionErrors <span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token builtin">error</span>
    spaceFreed <span class="token operator">:=</span> <span class="token function">int64</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span>
    <span class="token keyword">for</span> <span class="token boolean">_</span><span class="token punctuation">,</span> image <span class="token operator">:=</span> <span class="token keyword">range</span> images <span class="token punctuation">{</span>
        <span class="token operator">...</span><span class="token operator">...</span>

        <span class="token comment" spellcheck="true">// 略过最近使用时间距离现在小于设置的 MinAge 的镜像</span>
        <span class="token keyword">if</span> freeTime<span class="token punctuation">.</span><span class="token function">Sub</span><span class="token punctuation">(</span>image<span class="token punctuation">.</span>firstDetected<span class="token punctuation">)</span> <span class="token operator">&lt;</span> im<span class="token punctuation">.</span>policy<span class="token punctuation">.</span>MinAge <span class="token punctuation">{</span>
            <span class="token keyword">continue</span>
        <span class="token punctuation">}</span>

        <span class="token comment" spellcheck="true">// 删除镜像并更新 imageRecords 对象中缓存的镜像信息，记录删除的镜像大小</span>
        err <span class="token operator">:=</span> im<span class="token punctuation">.</span>runtime<span class="token punctuation">.</span><span class="token function">RemoveImage</span><span class="token punctuation">(</span>container<span class="token punctuation">.</span>ImageSpec<span class="token punctuation">{</span>Image<span class="token punctuation">:</span> image<span class="token punctuation">.</span>id<span class="token punctuation">}</span><span class="token punctuation">)</span>
        <span class="token keyword">if</span> err <span class="token operator">!=</span> <span class="token boolean">nil</span> <span class="token punctuation">{</span>
            deletionErrors <span class="token operator">=</span> <span class="token function">append</span><span class="token punctuation">(</span>deletionErrors<span class="token punctuation">,</span> err<span class="token punctuation">)</span>
            <span class="token keyword">continue</span>
        <span class="token punctuation">}</span>
        <span class="token function">delete</span><span class="token punctuation">(</span>im<span class="token punctuation">.</span>imageRecords<span class="token punctuation">,</span> image<span class="token punctuation">.</span>id<span class="token punctuation">)</span>
        spaceFreed <span class="token operator">+=</span> image<span class="token punctuation">.</span>size

        <span class="token comment" spellcheck="true">// 如果删除的镜像大小满足需求，停止继续删除</span>
        <span class="token keyword">if</span> spaceFreed <span class="token operator">>=</span> bytesToFree <span class="token punctuation">{</span>
            <span class="token keyword">break</span>
        <span class="token punctuation">}</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">if</span> <span class="token function">len</span><span class="token punctuation">(</span>deletionErrors<span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> spaceFreed<span class="token punctuation">,</span> fmt<span class="token punctuation">.</span><span class="token function">Errorf</span><span class="token punctuation">(</span><span class="token string">"wanted to free %d, but freed %d space with errors in image deletion: %v"</span><span class="token punctuation">,</span> bytesToFree<span class="token punctuation">,</span> spaceFreed<span class="token punctuation">,</span> errors<span class="token punctuation">.</span><span class="token function">NewAggregate</span><span class="token punctuation">(</span>deletionErrors<span class="token punctuation">)</span><span class="token punctuation">)</span>
    <span class="token punctuation">}</span>
    <span class="token keyword">return</span> spaceFreed<span class="token punctuation">,</span> <span class="token boolean">nil</span>
<span class="token punctuation">}</span>
</code></pre>
<p><code>realImageGCManager</code> 缓存了当前节点使用的镜像信息，并在 <code>Start()</code> 方法中启动两个 goroutine 周期性地去更新缓存的内容。<code>GarbageCollect</code> 的逻辑是这样的：</p>
<ul>
<li>调用 cAdvisor 接口获取镜像所在磁盘的文件系统信息，根据当前的使用量和配置的 GC 策略确定是否需要进行清理</li>
<li>如果需要清理，计算需要清理的总大小，调用 <code>freeSpace</code> 进行镜像清理工作</li>
<li>把所有可以清理的镜像根据使用时间进行排序，进行逐个清理，知道清理的镜像总大小满足需求才停止</li>
</ul>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>容器和镜像 GC 的内容相对比较独立，而且逻辑也不是很复杂，源代码也很容易理解。但这部分内容却非常重要，影响到节点的正常工作状况，最后总结几点需要注意的地方：</p>
<ul>
<li>默认情况下，container GC 是每分钟进行一次，image GC 是每五分钟一次，如果有不同的需要，可以通过 kubelet 的启动参数进行修改</li>
<li>不要手动清理镜像和容器，因为 kubelet 运行的时候会保存当前节点上镜像和容器的缓存，并定时更新。手动清理镜像和容器会让 kubelet 做出误判，带来不确定的问题</li>
<li>不是 kubelet 管理的容器不在 GC 的范围内，也就是说用户手动通过 docker 创建的容器不会被 kubelet 删除</li>
</ul>
<p><strong>NOTE</strong>：GC 机制后面会被 eviction 机制替代，可以在官方文档查看 <a href="https://github.com/kubernetes/community/blob/master/contributors/design-proposals/kubelet-eviction.md" target="_blank" rel="noopener"> eviction 的设计</a>。</p>
<h2 id="参考资料"><a href="#参考资料" class="headerlink" title="参考资料"></a>参考资料</h2><ul>
<li><a href="https://kubernetes.io/docs/concepts/cluster-administration/kubelet-garbage-collection/" target="_blank" rel="noopener">Configuring kubelet Garbage Collection</a></li>
<li><a href="https://kubernetes.io/docs/tasks/administer-cluster/out-of-resource/" target="_blank" rel="noopener">Configuring Out Of Resource Handling</a></li>
<li><a href="https://blog.kublr.com/learn-how-kubelet-eviction-policies-impact-cluster-rebalancing-2e976ebc53ea" target="_blank" rel="noopener">Learn how kubelet eviction policies impact cluster rebalancing</a></li>
<li><a href="https://kubernetes.cn/topics/48" target="_blank" rel="noopener">谈 Kubernetes 如何控制 Node 的资源使用</a></li>
<li><a href="http://www.cnblogs.com/openxxs/p/5275051.html" target="_blank" rel="noopener">Kubernetes中的垃圾回收机制</a></li>
<li><a href="http://dockone.io/article/2134" target="_blank" rel="noopener">Kubelet源码分析（三）：Garbage Collection</a></li>
<li><a href="https://github.com/kubernetes/community/blob/master/contributors/design-proposals/kubelet-eviction.md" target="_blank" rel="noopener">Kubelet - Eviction Policy Proposals Doc</a></li>
<li><a href="https://github.com/kubernetes/kubernetes/issues/31362" target="_blank" rel="noopener">Kubelet evictions - whats remaining?</a></li>
</ul>

                </div>
            </section>
        </article>
    </div>
    
<nav class="pagination">
    
    
    <a class="prev-post" title="kubelet 源码分析：statusManager 和 probeManager" href="/2017/06/12/kubelet-source-code-analysis-part4-status-manager/">
        ← kubelet 源码分析：statusManager 和 probeManager
    </a>
    
    <span class="prev-next-post">•</span>
    
    <a class="next-post" title="kubelet 源码分析：pod 新建流程" href="/2017/06/07/kubelet-source-code-analysis-part-2/">
        kubelet 源码分析：pod 新建流程 →
    </a>
    
    
</nav>

    <div class="inner">
    <!-- Begin Mailchimp Signup Form -->
    <link href="//cdn-images.mailchimp.com/embedcode/classic-10_7.css" rel="stylesheet" type="text/css">
    <style type="text/css">
    	#mc_embed_signup{background:#fff; clear:left; font:14px Helvetica,Arial,sans-serif; }
    	/* Add your own Mailchimp form style overrides in your site stylesheet or in this style block.
    	   We recommend moving this block and the preceding CSS link to the HEAD of your HTML file. */
    </style>
    <div id="mc_embed_signup">
    <form action="https://cizixs.us7.list-manage.com/subscribe/post?u=2d561b8dea52d73a2e05e6dcb&amp;id=5c710f135b" method="post" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank" novalidate>
        <div id="mc_embed_signup_scroll">
    	<h2>订阅本博客，第一时间收到文章更新</h2>
    <div class="indicates-required"><span class="asterisk">*</span> indicates required</div>
    <div class="mc-field-group">
    	<label for="mce-EMAIL">邮件地址  <span class="asterisk">*</span>
    </label>
    	<input type="email" value="" name="EMAIL" class="required email" id="mce-EMAIL">
    </div>
    	<div id="mce-responses" class="clear">
    		<div class="response" id="mce-error-response" style="display:none"></div>
    		<div class="response" id="mce-success-response" style="display:none"></div>
    	</div>    <!-- real people should not fill this in and expect good things - do not remove this or risk form bot signups-->
        <div style="position: absolute; left: -5000px;" aria-hidden="true"><input type="text" name="b_2d561b8dea52d73a2e05e6dcb_5c710f135b" tabindex="-1" value=""></div>
        <div class="clear"><input type="submit" value="Subscribe" name="subscribe" id="mc-embedded-subscribe" class="button"></div>
        </div>
    </form>
    </div>
    <script type='text/javascript' src='//s3.amazonaws.com/downloads.mailchimp.com/js/mc-validate.js'></script><script type='text/javascript'>(function($) {window.fnames = new Array(); window.ftypes = new Array();fnames[0]='EMAIL';ftypes[0]='email';}(jQuery));var $mcj = jQuery.noConflict(true);</script>
    <!--End mc_embed_signup-->
    </div>

    <div class="inner">
        <div id="disqus_thread"></div>
    </div>

    
</main>

<div class="t-g-control">
    <div class="gotop">
        <svg class="icon" width="32px" height="32px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M793.024 710.272a32 32 0 1 0 45.952-44.544l-310.304-320a32 32 0 0 0-46.4 0.48l-297.696 320a32 32 0 0 0 46.848 43.584l274.752-295.328 286.848 295.808z" fill="#8a8a8a" /></svg>
    </div>
    <div class="toc-control">
        <svg class="icon toc-icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M779.776 480h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M779.776 672h-387.2a32 32 0 0 0 0 64h387.2a32 32 0 0 0 0-64M256 288a32 32 0 1 0 0 64 32 32 0 0 0 0-64M392.576 352h387.2a32 32 0 0 0 0-64h-387.2a32 32 0 0 0 0 64M256 480a32 32 0 1 0 0 64 32 32 0 0 0 0-64M256 672a32 32 0 1 0 0 64 32 32 0 0 0 0-64" fill="#8a8a8a" /></svg>
        <svg class="icon toc-close" style="display: none;" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M512 960c-247.039484 0-448-200.960516-448-448S264.960516 64 512 64 960 264.960516 960 512 759.039484 960 512 960zM512 128.287273c-211.584464 0-383.712727 172.128262-383.712727 383.712727 0 211.551781 172.128262 383.712727 383.712727 383.712727 211.551781 0 383.712727-172.159226 383.712727-383.712727C895.712727 300.415536 723.551781 128.287273 512 128.287273z" fill="#8a8a8a" /><path d="M557.05545 513.376159l138.367639-136.864185c12.576374-12.416396 12.672705-32.671738 0.25631-45.248112s-32.704421-12.672705-45.248112-0.25631l-138.560301 137.024163-136.447897-136.864185c-12.512727-12.512727-32.735385-12.576374-45.248112-0.063647-12.512727 12.480043-12.54369 32.735385-0.063647 45.248112l136.255235 136.671523-137.376804 135.904314c-12.576374 12.447359-12.672705 32.671738-0.25631 45.248112 6.271845 6.335493 14.496116 9.504099 22.751351 9.504099 8.12794 0 16.25588-3.103239 22.496761-9.247789l137.567746-136.064292 138.687596 139.136568c6.240882 6.271845 14.432469 9.407768 22.65674 9.407768 8.191587 0 16.352211-3.135923 22.591372-9.34412 12.512727-12.480043 12.54369-32.704421 0.063647-45.248112L557.05545 513.376159z" fill="#8a8a8a" /></svg>
    </div>
    <div class="gobottom">
        <svg class="icon" width="32px" height="32.00px" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg"><path d="M231.424 346.208a32 32 0 0 0-46.848 43.584l297.696 320a32 32 0 0 0 46.4 0.48l310.304-320a32 32 0 1 0-45.952-44.544l-286.848 295.808-274.752-295.36z" fill="#8a8a8a" /></svg>
    </div>
</div>
<div class="toc-main" style="right: -100%">
    <div class="post-toc">
        <span>TOC</span>
        <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#kubernetes-GC-简介"><span class="toc-text">kubernetes GC 简介</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#容器-Garbage-Collect"><span class="toc-text">容器 Garbage Collect</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#镜像-Garbage-Collect"><span class="toc-text">镜像 Garbage Collect</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#容器-GC-的代码分析"><span class="toc-text">容器 GC 的代码分析</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#镜像-GC-的代码"><span class="toc-text">镜像 GC 的代码</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#总结"><span class="toc-text">总结</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#参考资料"><span class="toc-text">参考资料</span></a></li></ol>
    </div>
</div>



        

<aside class="read-next outer">
    <div class="inner">
        <div class="read-next-feed">
            
            

<article class="read-next-card"  style="background-image: url(https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxcn9ft3j318w0txdo6.jpg)"  >
  <header class="read-next-card-header">
    <small class="read-next-card-header-sitetitle">&mdash; Cizixs Write Here &mdash;</small>
    <h3 class="read-next-card-header-title">Recent Posts</h3>
  </header>
  <div class="read-next-divider">
    <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
      <path d="M13 14.5s2 3 5 3 5.5-2.463 5.5-5.5S21 6.5 18 6.5c-5 0-7 11-12 11C2.962 17.5.5 15.037.5 12S3 6.5 6 6.5s4.5 3.5 4.5 3.5"/>
    </svg>
  </div>
  <div class="read-next-card-content">
    <ul>
      
      
      
      <li>
        <a href="/2018/08/26/what-is-istio/">什么是 istio</a>
      </li>
      
      
      
      <li>
        <a href="/2018/08/25/knative-serverless-platform/">serverless 平台 knative 简介</a>
      </li>
      
      
      
      <li>
        <a href="/2018/06/25/kubernetes-resource-management/">kubernetes 资源管理概述</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/24/use-prometheus-and-grafana-to-monitor-linux-machine/">使用 promethues 和 grafana 监控自己的 linux 机器</a>
      </li>
      
      
      
      <li>
        <a href="/2018/01/13/linux-udp-packet-drop-debug/">linux 系统 UDP 丢包问题分析思路</a>
      </li>
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    </ul>
  </div>
  <footer class="read-next-card-footer">
    <a href="/archives">  MORE  → </a>
  </footer>
</article>


            
            
            
        </div>
    </div>
</aside>


<footer class="site-footer outer">

	<div class="site-footer-content inner">
		<section class="copyright">
			<a href="/" title="Cizixs Write Here">Cizixs Write Here</a>
			&copy; 2019
		</section>
		<nav class="site-footer-nav">
			
            <a href="https://hexo.io" title="Hexo" target="_blank" rel="noopener">Hexo</a>
            <a href="https://github.com/xzhih/hexo-theme-casper" title="Casper" target="_blank" rel="noopener">Casper</a>
        </nav>
    </div>
</footer>






<div class="floating-header" >
	<div class="floating-header-logo">
        <a href="/" title="Cizixs Write Here">
			
                <img src="https://cizixs-blog.oss-cn-beijing.aliyuncs.com/006tNc79ly1g1qxfovpzyj30740743yg.jpg" alt="Cizixs Write Here icon" />
			
            <span>Cizixs Write Here</span>
        </a>
    </div>
    <span class="floating-header-divider">&mdash;</span>
    <div class="floating-header-title">kubelet 源码分析：Garbage Collect</div>
    <progress class="progress" value="0">
        <div class="progress-container">
            <span class="progress-bar"></span>
        </div>
    </progress>
</div>
<script>
   $(document).ready(function () {
    var progressBar = document.querySelector('progress');
    var header = document.querySelector('.floating-header');
    var title = document.querySelector('.post-full-title');
    var lastScrollY = window.scrollY;
    var lastWindowHeight = window.innerHeight;
    var lastDocumentHeight = $(document).height();
    var ticking = false;

    function onScroll() {
        lastScrollY = window.scrollY;
        requestTick();
    }
    function requestTick() {
        if (!ticking) {
            requestAnimationFrame(update);
        }
        ticking = true;
    }
    function update() {
        var rect = title.getBoundingClientRect();
        var trigger = rect.top + window.scrollY;
        var triggerOffset = title.offsetHeight + 35;
        var progressMax = lastDocumentHeight - lastWindowHeight;
            // show/hide floating header
            if (lastScrollY >= trigger + triggerOffset) {
                header.classList.add('floating-active');
            } else {
                header.classList.remove('floating-active');
            }
            progressBar.setAttribute('max', progressMax);
            progressBar.setAttribute('value', lastScrollY);
            ticking = false;
        }

        window.addEventListener('scroll', onScroll, {passive: true});
        update();

        // TOC
        var width = $('.toc-main').width();
        $('.toc-control').click(function () {
            if ($('.t-g-control').css('width')=="50px") {
                if ($('.t-g-control').css('right')=="0px") {
                    $('.t-g-control').animate({right: width}, "slow");
                    $('.toc-main').animate({right: 0}, "slow");
                    toc_icon()
                } else {
                    $('.t-g-control').animate({right: 0}, "slow");
                    $('.toc-main').animate({right: -width}, "slow");
                    toc_icon()
                }
            } else {
                if ($('.toc-main').css('right')=="0px") {
                    $('.toc-main').slideToggle("fast", toc_icon());
                } else {
                    $('.toc-main').css('right', '0px');
                    toc_icon()
                }
            }
        })

        function toc_icon() {
            if ($('.toc-icon').css('display')=="none") {
                $('.toc-close').hide();
                $('.toc-icon').show();
            } else {
                $('.toc-icon').hide();
                $('.toc-close').show();
            }
        }

        $('.gotop').click(function(){
            $('html,body').animate({scrollTop:$('.post-full-header').offset().top}, 800);
        });
        $('.gobottom').click(function () {
            $('html,body').animate({scrollTop:$('.pagination').offset().top}, 800);
        });

        // highlight
        // https://highlightjs.org
        $('pre code').each(function(i, block) {
            hljs.highlightBlock(block);
        });
        $('td.code').each(function(i, block) {
            hljs.highlightBlock(block);
        });

        console.log("this theme is from https://github.com/xzhih/hexo-theme-casper")
    });
</script>



<link rel="stylesheet" href="https://cdn.staticfile.org/lightgallery/1.3.9/css/lightgallery.min.css">



<script src="https://cdn.staticfile.org/lightgallery/1.3.9/js/lightgallery.min.js"></script>


<script>
	$(function () {
		var postImg = $('#lightgallery').find('img');
		postImg.addClass('post-img');
		postImg.each(function () {
			var imgSrc = $(this).attr('src');
			$(this).attr('data-src', imgSrc);
		});
		$('#lightgallery').lightGallery({selector: '.post-img'});
	});
</script>



<script>

/**
*  RECOMMENDED CONFIGURATION VARIABLES: EDIT AND UNCOMMENT THE SECTION BELOW TO INSERT DYNAMIC VALUES FROM YOUR PLATFORM OR CMS.
*  LEARN WHY DEFINING THESE VARIABLES IS IMPORTANT: https://disqus.com/admin/universalcode/#configuration-variables*/

var disqus_config = function () {
this.page.url = 'http://cizixs.com/2017/06/09/kubelet-source-code-analysis-part-3/';  // Replace PAGE_URL with your page's canonical URL variable
this.page.identifier = 'http://cizixs.com/2017/06/09/kubelet-source-code-analysis-part-3/'; // Replace PAGE_IDENTIFIER with your page's unique identifier variable
};

(function() { // DON'T EDIT BELOW THIS LINE
var d = document, s = d.createElement('script');
s.src = 'https://cizixs.disqus.com/embed.js';
s.setAttribute('data-timestamp', +new Date());
(d.head || d.body).appendChild(s);
})();
</script>
<noscript>Please enable JavaScript to view the <a href="https://disqus.com/?ref_noscript">comments powered by Disqus.</a></noscript>
                            


    </div>
</body>
</html>
